// -*- c-basic-offset: 2 default-tab-width: 2 indent-tabs-mode: t -*-
// vim: autoindent tabstop=2 noexpandtab shiftwidth=2 softtabstop=2
#ifndef __UTIL_H
#	define __UTIL_H

#if defined(__GNUC__) && !defined(inline)
#	define inline inline __attribute__((always_inline))
#endif
# include "config.h"

# define WORD	"%"PRIu64
# define XWORD	"%"PRIx64

#include "vmkit/Locks.h"
#include "vmkit/System.h"
#include "VmkitGC.h"
#include "vmkit/Allocator.h"


#define R_VAL(__type, __var, __val)\
  __type __var = NULL;\
  llvm_gcroot(__var, 0); \
  __var = __val

#define R_VAR(__type, __var)\
  __type __var = NULL;\
  llvm_gcroot(__var, 0)

#define R_REF_VAR(__type, __var)\
		__type __var = NULL;\
		__llvm_gcroot((void**)__var, 0);

#define R_PARAM(__var)\
  llvm_gcroot(__var, 0)

#define R_REF_PARAM(__var)\
		__llvm_gcroot((void**)__var, 0);

#define asSelf(T)\
  T* self = this;\
  llvm_gcroot(self, 0)

#if defined(R_DEBUG)
# define ddo(...) __VA_ARGS__
#else
# define ddo(...)
#endif

#if defined(R_JIT_DEBUG)
# define jitddo(...) __VA_ARGS__
#else
# define jitddo(...)
#endif


extern void recho(const char* msg, const char* fmt, ...)__attribute__((noinline));
void do_rfatal(const char* fn, uint64_t ln, const char* fct, const char* fmt, ...) __attribute__((noreturn));

#define warning(...)\
  recho("warning", __VA_ARGS__)
#define rfatal(...)\
  do_rfatal(__FILE__, __LINE__, __PRETTY_FUNCTION__, __VA_ARGS__)
#define rerror_on(__test, ...)\
  if(__test)\
	rfatal("assertion failed '" #__test "':\t" __VA_ARGS__)

#define rprintf(...)\
  ddo(recho("info",    __VA_ARGS__))
#define jitprintf(...)\
  jitddo(recho("jit-debug",    __VA_ARGS__))

#define Assert(__test, ...)\
  ddo(rerror_on(!(__test), __VA_ARGS__))

#define nyi_fatal()\
  rfatal("not yet implemented")

#define nyi()					\
  ({ static int z_nyi=0; if(!z_nyi) { z_nyi=1; fprintf(stderr, "Not yet implemented at %s::%d (%s)\n", __FILE__, __LINE__, __PRETTY_FUNCTION__); }}) 

#define PrintNewLine()\
	puts("")

#define debugTraceFunction() ddo(if(es>EVAL_TO_EVAL){fflush(NULL); fprintf(stderr, "[jit-info]\t%s\n", __PRETTY_FUNCTION__); fflush(NULL);})

// Use the fast version iff l > r
#define mod_iterate_fast(i, i2, n, n2) for (i=i2=0; i < n; \
		    i2 = (++i2 == n2) ? 0 : i2, ++i)

#define mod_iterate(n, n1, n2, i1, i2) for (int i=i1=i2=0; i<n; \
		    i1 = (++i1 == n1) ? 0 : i1,\
		    i2 = (++i2 == n2) ? 0 : i2,\
		    ++i)

template <typename T>
static inline void swap(T& one, T& other) {
	T& tmp = one;
	one = other;
	other = tmp;
}

template <typename T>
static inline T max(T one, T other) {
	return one > other ? one : other;
}

template <typename T>
static inline T& min(T& one, T& other) {
	return one < other ? one : other;
}

// TODO remove this swap to use the first one
// but ensure the code is WELL generate (-O0 don't do it)
#define SWAP(__x, __y) do{\
		typeof(__x) __tmp_swap = __x;\
		__x = __y;\
		__y = __tmp_swap;\
	}while(0)


#define TC_CASE(x, ...)\
	case (x::ID) >> SXP_LOW_PART: __VA_ARGS__ ; break;

#define TC_BRANCH

#define TC_BRANCHInt(...)\
	TC_CASE(Int, __VA_ARGS__)
#define TC_BRANCHDouble(...)\
	TC_CASE(Double, __VA_ARGS__)
#define TC_BRANCHLogical(...)\
	TC_CASE(Logical, __VA_ARGS__)
#define TC_BRANCHString(...)\
	TC_CASE(String, __VA_ARGS__)
#define TC_BRANCHVector(...)\
	TC_CASE(Vector, __VA_ARGS__)
#define TC_BRANCHDefault(...)\
	default:do{ __VA_ARGS__ ; }while(0);

#define TC_BRANCHES(b1, b2, b3, b4, b5, b6, ...)\
	TC_BRANCH##b1 TC_BRANCH##b2 TC_BRANCH##b3 TC_BRANCH##b4\
	TC_BRANCH##b5 TC_BRANCH##b6

#define TYPECASE(__x, ...)\
	switch((__x) >> SXP_LOW_PART){\
		TC_BRANCHES(__VA_ARGS__,,,,,,,)\
	}

#endif
